当浏览器加载页面时,它会“读取”(或者称之为:“解析”)HTML 并从中生成 DOM 对象。对于元素节点,大多数标准的 HTML 特性(attributes)会自动变成 DOM 对象的属性(properties)
但特性与属性映射并不是一一对应的!
浏览器解析 HTML 文本,并根据标签创建 DOM 对象,会辨别标准的特性(attribute)并以此创建 DOM 属性(properties),但是非标准的特性则不会:
<body id="test" something="non-standard">
<script>
// 标准特性会添加到 DOM 属性
console.log(document.body.id) // test
// 非标准的特性不会
console.log(document.body.something); // undefined
</script>
</body>
注意:
"type" 是 <input> 的一个标准特性(HTMLInputElement),但对于 <body>(HTMLBodyElement)来说则不是可以使用 elem.attributes 读取所有 attribute,属于内建 Attr 类的对象的集合,具有 name 和 value 属性:
for (let attr of elem.attributes) {
console.log(attr.name, attr.value)
}
所有 attribute 都可以通过使用以下方法进行访问:
elem.hasAttribute(key) —— 检查特性是否存在elem.getAttribute(key) —— 获取这个特性值elem.setAttribute(key, value) —— 设置这个特性值elem.removeAttribute(name) —— 移除这个特性其中,key 和 value 都是字符串类型(因为其操作的实际上是 HTML 中的内容),不是字符串的话会进行 [[002.数据类型#隐式类型转换|隐式类型转换]]
即:
同时还有相应的 elem.*AttributeNS() 方法,用于 [[002.DOM:节点与集合#命名空间|命名空间]]。
当一个标准的 attribute 被改变,对应的 property 也会自动更新(除了几个特例),反之亦然。
<input>
<script>
let input = document.querySelector('input');
// 特性 => 属性
input.setAttribute('id', 'id');
alert(input.id); // id(被更新了)
// 属性 => 特性
input.id = 'newId';
alert(input.getAttribute('id')); // newId(被更新了)
</script>
例外,例如 input.value 只能从 attribute 同步到 property,反过来则不行:
<input>
<script>
let input = document.querySelector('input');
// 特性 => 属性
input.setAttribute('value', 'text');
alert(input.value); // text
// 这个操作无效,属性 => 特性
input.value = 'newValue';
alert(input.getAttribute('value')); // text(没有被更新!)
</script>
DOM 节点是常规的 JS 对象,可以向普通 JS 对象一样操作:
// 添加属性
document.body.myData = {
name: 'Caesar',
title: 'Imperator'
}
console.log(document.body.myData.title) // 'Imperator'
// 添加方法
document.body.sayTagName = function() {
alert(this.tagName)
}
document.body.sayTagName() // BODY
// 修改原型
Element.prototype.sayHi = function() {
alert(`Hello, I'm ${this.tagName}`)
}
document.documentElement.sayHi() // Hello, I'm HTML
document.body.sayHi() // Hello, I'm BODY
// ...
property 不总是字符串类型。例如,input.checked 属性(type="checkbox")是布尔型:
<input id="input" type="checkbox" checked>checkbox</input>
<script>
console.log(input.getAttribute('checked')) // ""
console.log(input.checked) // true
</script>
还有其他的例子:style 属性是一个对象:
<div id="div" style="color:red;font-size:120%">Hello</div>
<script>
// 字符串
console.log(div.getAttribute('style')) // "color:red;font-size:120%"
// 对象
console.log(div.style) // [object CSSStyleDeclaration]
console.log(div.style.color) // "red"
</script>
还有 property 是字符串类型,但它和 attribute 不同。例如,href property 一直是一个完整的 URL:
<a id="a" href="#hello">link</a>
<script>
console.log(a.getAttribute('href')) // "#hello"
console.log(a.href) // "http://localhost:8080/page#hello"
</script>
data-*所有以 “data-” 开头的 attribute 均被保留供程序员使用。它们可在 dataset property 中使用:
<div id="order" data-order-state="123">A new order.</div>
<script>
// 读取
console.log(order.dataset.orderState) // "123"
// 修改
order.dataset.orderState = "pending"
</script>
使用 data-* 特性是一种合法且安全的传递自定义数据的方式。
注意:
data-order-state;property:dataset.orderState
data-orderState;property:dataset.orderstate